// Copyright 2013 Ronald Schlenker, www.technewlogic.de.
// 
// This file is part of Byond.
// 
// Byond is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
// 
// Byond is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with Byond.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows;
using Byond.OnlineDebugging;

namespace Byond.Frontend.OnlineDebugging.ViewModels
{
	public class InspectionNodeViewModel
	{
		public InspectionNodeViewModel(object instance, string memberName, Type instanceType)
		{
			MemberName = memberName;
			_instanceType = instanceType;
			_instance = instance ?? new NullReference();
		}

		private readonly object _instance;
		private readonly Type _instanceType;

		public string Value { get { return _instance.ToString(); } }
		public string MemberName { get; private set; }
		public string TypeName { get { return _instanceType.Name; } }

		public IEnumerable<InspectionNodeViewModel> Children
		{
			get
			{
				if (_instanceType.IsPrimitive || typeof(string).IsAssignableFrom(_instanceType))
					return Enumerable.Empty<InspectionNodeViewModel>();
				
				if (typeof(IEnumerable).IsAssignableFrom(_instanceType))
				{
					var enumerableInstance = ((IEnumerable)_instance).OfType<object>();
					if (enumerableInstance.Count() > 100)
						MessageBox.Show("There are too many results - only the first 100 results will be shown.");
					return enumerableInstance
						.Take(100)
						.Select(it => new InspectionNodeViewModel(
							it, string.Empty, NullReference.GetValue(it).GetType()))
						.ToArray();
				}

				return _instanceType
					.GetProperties(
						BindingFlags.Public
						| BindingFlags.NonPublic
						| BindingFlags.Instance)
					.Select(it =>
						{
							try
							{
								var value = it.GetValue(_instance, null);
								return new InspectionNodeViewModel(
									value, it.Name, it.PropertyType);
							}
							catch
							{
								return new InspectionNodeViewModel(
									new PropertyGetError(), it.Name, it.PropertyType);
							}
						})
					.ToArray();
			}
		}
	}
}
